#include "STable.h"

#include <core/StyleMgr.h>

#include <QFile>
#include <QFont>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QPainter>
#include <QScrollBar>
#include <QTableView>
#include <QWheelEvent>

static const int FLASH_NUMBER = 15;  // 200ms * 15
static const int ROW_HEIGHT = 24;

DefaulTableItemDelegate::DefaulTableItemDelegate(QObject* p)
    : QStyledItemDelegate(p) {}

void DefaulTableItemDelegate::paint(QPainter* painter,
                                    const QStyleOptionViewItem& option,
                                    const QModelIndex& index) const {
  painter->setPen(StyleMgr::instance().color("BasicPlate"));
  painter->drawRect(option.rect);
  QStyleOptionViewItem itemOption(option);
  // 去掉选中时的虚线框
  if (itemOption.state & QStyle::State_HasFocus)
    itemOption.state = itemOption.state ^ QStyle::State_HasFocus;

  itemOption.palette.setColor(QPalette::Highlight,
                              StyleMgr::instance().color("MenuTitleHover"));
  // 选中字体颜色不变
  itemOption.palette.setColor(QPalette::HighlightedText,
                              index.data(Qt::ForegroundRole).value<QColor>());

  // 图片位置修正
  if ((index.data(Qt::TextAlignmentRole).toInt() & Qt::AlignRight) ==
      Qt::AlignRight)
    itemOption.decorationPosition = QStyleOptionViewItem::Right;

  QString id = index.data(DataIdRole).value<QString>();
  QString idSel = index.data(DataSelIdRole).value<QString>();
  QPixmap prefixImg = index.data(PrefixImgRole).value<QPixmap>();
  QPixmap postfixImg = index.data(PostfixImgRole).value<QPixmap>();
  QString postfixTxt = index.data(PostfixTxtRole).value<QString>();
  QRect postfixTxtRect = index.data(PostfixTxtRectRole).value<QRect>();
  QString specialLabel = index.data(SpecialLabelRole).value<QString>();

  if (!prefixImg.isNull() || !postfixImg.isNull() || !postfixTxt.isEmpty() ||
      !specialLabel.isEmpty()) {
    painter->save();
    initStyleOption(&itemOption, index);
    painter->fillRect(itemOption.rect,
                      !idSel.isEmpty() && idSel == id
                          ? itemOption.palette.color(QPalette::Highlight)
                          : itemOption.backgroundBrush);

    const QString& txt = index.data(Qt::DisplayRole).toString();
    const QFont& font = index.data(Qt::FontRole).value<QFont>();
    const int txtWidth = QFontMetrics(font).width(txt);
    const Qt::Alignment align =
        static_cast<Qt::Alignment>(index.data(Qt::TextAlignmentRole).toInt());

    QRect prefixRect, txtRect, postfixRect, postfixRect2;
    {
      const int spacing = 1;
      txtRect.setSize(itemOption.rect.size());
      if (!prefixImg.isNull()) {
        prefixRect.setSize(prefixImg.size());
        txtRect.setWidth(txtRect.width() - prefixImg.width() - spacing);
      }
      if (!postfixImg.isNull()) {
        postfixRect.setSize(postfixImg.size());
        txtRect.setWidth(txtRect.width() - postfixImg.width() - spacing);
      }
      if (!postfixTxt.isEmpty()) {
        postfixRect2.setSize(postfixTxtRect.size());
        txtRect.setWidth(txtRect.width() - postfixTxtRect.width() - spacing);
      }
      int shrunk = 3;  // default for Qt::AlignLeft, with some pixel shrunk
      if (txtWidth < txtRect.width()) {
        const int blankWidth = txtRect.width() - txtWidth;
        txtRect.setWidth(txtWidth);
        if (align & Qt::AlignRight) {
          shrunk = blankWidth - shrunk;
        } else if (align & Qt::AlignHCenter) {
          shrunk = blankWidth / 2;
        }
      }
      shrunk += itemOption.rect.x();
      prefixRect.moveTo(shrunk, itemOption.rect.y());
      if (prefixRect.isValid()) shrunk += (spacing + prefixRect.width());
      if (postfixRect.isValid()) shrunk -= 2;
      txtRect.moveTo(shrunk, itemOption.rect.y());
      shrunk += (spacing + txtRect.width());
      if (postfixRect.isValid())
        postfixRect.moveTo(shrunk + 2,
                           itemOption.rect.y() + itemOption.rect.height() / 2);
      if (postfixRect2.isValid())
        postfixRect2.moveTo(shrunk + 2,
                            itemOption.rect.y() + itemOption.rect.height() / 2);
    }

    QRect r = itemOption.rect;
    r.setRight(r.right() - 4);
    if (!postfixImg.isNull()) {
      // painter->drawPixmap(r.right() - postfixImg.width() /
      // postfixImg.devicePixelRatioF(), r.bottom() - postfixImg.height() /
      // postfixImg.devicePixelRatioF() - 4, postfixImg);//TODO DPI
      // r.setRight(r.right() - postfixImg.width() /
      // postfixImg.devicePixelRatioF() - 2);
      painter->drawPixmap(postfixRect, postfixImg);
    }
    if (!postfixTxt.isEmpty()) {
      painter->setPen(index.data(PostfixTxtRectColor).value<QColor>());
      painter->drawText(postfixRect2, postfixTxt,
                        QTextOption(Qt::AlignCenter | Qt::AlignVCenter));
    }

    painter->setPen(index.data(Qt::ForegroundRole).value<QColor>());
    painter->setFont(font);
    // painter->drawText(r, txt, QTextOption(Qt::AlignRight |
    // Qt::AlignVCenter));
    {
      QTextOption to(align);
      to.setWrapMode(QTextOption::NoWrap);
      painter->drawText(txtRect, txt, to);
    }

    if (!specialLabel.isEmpty()) {
      QRect rcText = painter->boundingRect(txtRect, align, txt);
      QRect rcLabel(rcText.right() + 4, rcText.top(), rcText.width(),
                    rcText.height());
      QFont fontLabel = font;
      fontLabel.setPixelSize(10);
      painter->setFont(fontLabel);
      painter->setPen(StyleMgr::instance().color("InnerBorder"));
      QFontMetrics fm = painter->fontMetrics();

      QStringList strArr = specialLabel.split("|");
      for (int i = 0; i < strArr.length(); ++i) {
        rcLabel.setWidth(fm.boundingRect(strArr[i]).width() + 4);

        if (rcLabel.right() > itemOption.rect.right() - 4) {
          fontLabel.setPixelSize(8);
          painter->setFont(fontLabel);
          painter->setPen(StyleMgr::instance().color("TextNormal"));
          painter->drawText(rcLabel, "...",
                            QTextOption(Qt::AlignLeft | Qt::AlignBottom));
          break;
        } else {
          painter->drawRoundedRect(rcLabel.adjusted(0, 2, 0, -2), 2, 2);
          painter->drawText(rcLabel, strArr[i],
                            QTextOption(Qt::AlignCenter | Qt::AlignVCenter));
        }

        rcLabel.setLeft(rcLabel.right() + 3);
      }
    }

    if (!prefixImg.isNull()) {
      // QFontMetrics fm(painter->font());
      // int w = fm.horizontalAdvance(txt);
      // r.setRight(r.right() - w - 2);

      // painter->drawPixmap(r.right() - prefixImg.width() /
      // postfixImg.devicePixelRatioF(), r.center().y() - prefixImg.height() /
      // postfixImg.devicePixelRatioF() / 2, prefixImg);
      painter->drawPixmap(prefixRect, prefixImg);
    }
    painter->restore();
  } else {
    if (!idSel.isEmpty() && idSel == id) {
      itemOption.state |= QStyle::State_Selected;
    } else {
      itemOption.state &= ~(static_cast<int>(QStyle::State_Selected));
    }

    QStyledItemDelegate::paint(painter, itemOption, index);
  }

  //	painter->setPen(StyleMgr::instance().color("PartPlate"));
  //	painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
}

SVirtualTable::SVirtualTable(QWidget* p, QHeaderView* header) : QWidget(p) {
  QHBoxLayout* l = new QHBoxLayout(this);
  l->setContentsMargins(0, 0, 0, 0);
  l->setSpacing(0);
  setLayout(l);

  m_table = new QTableView(this);
  m_table->setAutoScroll(false);
  m_table->installEventFilter(this);
  m_table->setStyleSheet(
      QString("QTableView{background-color:#%1;border:0px solid white;}")
          .arg(StyleMgr::instance().color("BasicPlate").rgb(), 0, 16));

  if (nullptr != header) {
    m_table->setHorizontalHeader(header);
  }

  QFont headerFont = font();
  headerFont.setWeight(QFont::Normal);
  // headerFont.setBold(true);
  m_table->horizontalHeader()->setFont(headerFont);
  m_table->horizontalHeader()->setHighlightSections(false);
  m_table->horizontalHeader()->setMinimumSectionSize(
      0);  // 需设定，否则Linux上默认太大，导致列数较少时，仍然有水平滚动条
  m_table->horizontalHeader()->setStyleSheet(
      QString(
          "QHeaderView::section {"
          "background-color: #%1;color:#%2; padding-left: 4px;padding-right: "
          "4px;height:24px;border:none;border-right:1px solid #%3}")
          .arg(StyleMgr::instance().color("TabBackNormal").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("TitleWord").rgb(), 0, 16)
          .arg(StyleMgr::instance().color("BasicPlate").rgb(), 0, 16));
  m_table->setShowGrid(false);
  m_table->verticalHeader()->hide();  // 隐藏默认显示的行头
  m_table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  m_table->setSelectionBehavior(
      QAbstractItemView::SelectRows);  // 设置选中时整行选中
  m_table->setEditTriggers(
      QAbstractItemView::NoEditTriggers);  // 设置表格属性只读，不能编辑
  m_table->verticalHeader()->setMinimumSectionSize(2);
  m_table->verticalHeader()->setMaximumSectionSize(1024);
  m_table->verticalHeader()->setDefaultSectionSize(
      32);  // TODO sectionSize的设置原理
  m_table->setItemDelegate(new DefaulTableItemDelegate(this));
  l->addWidget(m_table);

  m_scrollBar = new QScrollBar(this);
  m_scrollBar->hide();
  m_scrollBar->setValue(0);
  m_scrollBar->setFixedWidth(8);
  l->addWidget(m_scrollBar);

  connect(m_scrollBar, &QScrollBar::valueChanged, this,
          &SVirtualTable::viewPosChanged);
  m_flashTimer = new QTimer(this);
  m_flashTimer->callOnTimeout(this, &SVirtualTable::onTimeOut);
}

void SVirtualTable::setRealDataCount(int c) {
  if (m_realDataCount != c) {
    m_realDataCount = c;
    resetScroll();
  }
}

int SVirtualTable::sliderPos() const { return m_scrollBar->value(); }

void SVirtualTable::resetScroll(bool resetPos /*= false*/) {
  if (m_pageCount < m_realDataCount)
    m_scrollBar->show();
  else
    m_scrollBar->hide();

  if (resetPos || m_scrollBar->value() > m_realDataCount)
    m_scrollBar->setValue(0);

  m_scrollBar->setRange(0, m_realDataCount - m_pageCount);
  m_scrollBar->setPageStep(m_pageCount);
  m_scrollBar->setSingleStep(1);
}

bool SVirtualTable::isVScrollBarShown() const {
  return m_pageCount < m_realDataCount;
}

bool SVirtualTable::eventFilter(QObject* watched, QEvent* event) {
  if ((watched == m_table || watched == m_frozenTable) &&
      event->type() == QEvent::Type::Wheel && m_realDataCount > m_pageCount) {
    const QWheelEvent* we = static_cast<QWheelEvent*>(event);

    int delta = we->angleDelta().y();
    int pos = m_scrollBar->value();
    int step = m_scrollBar->singleStep();
    int nMax = m_scrollBar->maximum();

    if (delta > 0) {
      pos -= step;
      pos = qMax(0, pos);
    } else {
      pos += step;
      pos = std::min(pos, nMax);
    }

    m_scrollBar->setValue(pos);
  } else if (watched == m_lockIndicator &&
             event->type() == QEvent::MouseButtonPress) {
    const QMouseEvent* me = dynamic_cast<QMouseEvent*>(event);
    if (me->buttons().testFlag(Qt::LeftButton)) {
      unlockTable();
      emit unlocked();
    }
  }

  return QWidget::eventFilter(watched, event);
}

void SVirtualTable::resizeEvent(QResizeEvent* event) {
  int pageCount = rect().height() / ROW_HEIGHT - 1;
  if (pageCount != m_pageCount) {
    m_pageCount = pageCount;
    resetScroll();

    auto* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
    if (myModel) myModel->setRowCount(m_pageCount);
  }

  emit viewPosChanged(m_scrollBar->value());

  updateLockGeo();
  updateFrozenTableGeometry();
}

void SVirtualTable::onTimeOut() {
  auto* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
  if (!myModel) return;

  if (!myModel->flash()) m_flashTimer->stop();
}

void SVirtualTable::addFlashInfo(const FlashInfo& fi, bool startImmediately) {
  auto* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
  if (!myModel) return;

  myModel->addFlashInfo(fi);
  if (startImmediately) {
    myModel->flash();
    m_flashTimer->start(200);
  }
}

void SVirtualTable::removeFlashInfo(const FlashInfo& fi) {
  auto* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
  if (!myModel) return;

  myModel->removeFlashInfo(fi);
}

void SVirtualTable::startFlash() {
  auto* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
  if (!myModel) return;

  if (myModel->flash()) m_flashTimer->start(200);
}

void SVirtualTable::setHeaderSortable(bool v) {
  m_headerSortable = v;
  if (m_headerSortable) {
    m_table->horizontalHeader()->setSectionsClickable(true);
    connect(m_table->horizontalHeader(), &QHeaderView::sectionPressed, this,
            &SVirtualTable::onHeaderClicked);
  }
}

void SVirtualTable::lockTable() { m_locked = true; }

void SVirtualTable::unlockTable() {
  if (m_locked && m_lockIndicator) {
    m_locked = false;
    m_lockIndicator->hide();
    m_lockIndicator->setText("");
  }
}

void SVirtualTable::selectItem(int row) {
  unSelectItem();

  if (nullptr == m_table) {
    return;
  }

  m_table->selectRow(row);
}

void SVirtualTable::unSelectItem() {
  if (nullptr == m_table) {
    return;
  }

  QItemSelectionModel* selectionModel = m_table->selectionModel();
  selectionModel->clearSelection();
}

void SVirtualTable::showLockNewData(const QString& tip) {
  if (!m_lockIndicator) {
    m_lockIndicator = new QLabel(this);
    QColor clr = StyleMgr::instance().color("Orange04");
    clr.setAlpha(0x80);
    m_lockIndicator->setStyleSheet(
        QString("background-color:#%1").arg(clr.rgba(), 0, 16));
    m_lockIndicator->setAlignment(Qt::AlignCenter);
    m_lockIndicator->installEventFilter(this);
  }

  m_lockIndicator->setText(tip);
  m_lockIndicator->raise();
  updateLockGeo();
  m_lockIndicator->show();
}

void SVirtualTable::setFrozenCols(int cols) {
  if (cols == 0) {
    if (m_frozenTable) {
      m_frozenTable->setParent(nullptr);
      m_frozenTable->deleteLater();
      m_frozenTable = nullptr;
    }
    return;
  }

  m_frozenCols = cols;
  if (m_frozenTable == nullptr) {
    m_frozenTable = new QTableView(this);
    m_frozenTable->installEventFilter(this);
    m_frozenTable->setStyleSheet(
        (QString("QTableView{background-color:#%1;border:0px solid white; "
                 "border-right:2px solid #253330;}")
             .arg(StyleMgr::instance().color("BasicPlate").rgb(), 0, 16)));
    m_frozenTable->setModel(m_table->model());
    m_frozenTable->setSelectionModel(m_table->selectionModel());

    m_frozenTable->setFocusPolicy(Qt::NoFocus);
    m_frozenTable->verticalHeader()->hide();
    m_frozenTable->horizontalHeader()->setSectionResizeMode(
        m_table->horizontalHeader()->sectionResizeMode(0));

    m_frozenTable->horizontalHeader()->setFont(
        m_table->horizontalHeader()->font());
    m_frozenTable->horizontalHeader()->setHighlightSections(false);
    m_frozenTable->horizontalHeader()->setMinimumSectionSize(
        0);  // 需设定，否则Linux上默认太大，导致列数较少时，仍然有水平滚动条
    m_frozenTable->horizontalHeader()->setStyleSheet(
        m_table->horizontalHeader()->styleSheet());
    m_frozenTable->setShowGrid(false);
    m_frozenTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_frozenTable->setSelectionBehavior(
        QAbstractItemView::SelectRows);  // 设置选中时整行选中
    m_frozenTable->setEditTriggers(
        QAbstractItemView::NoEditTriggers);  // 设置表格属性只读，不能编辑
    m_frozenTable->verticalHeader()->setMinimumSectionSize(2);
    m_frozenTable->verticalHeader()->setMaximumSectionSize(1024);
    m_frozenTable->verticalHeader()->setDefaultSectionSize(
        32);  // TODO sectionSize的设置原理
    m_frozenTable->setItemDelegate(new DefaulTableItemDelegate(this));

    // TODO:设置表头属性：fixed or?
    m_table->viewport()->stackUnder(m_frozenTable);
    for (int i = m_frozenCols; i < m_table->model()->columnCount(); ++i)
      m_frozenTable->setColumnHidden(i, true);

    for (int i = 0; i < m_frozenCols; ++i)
      m_frozenTable->setColumnWidth(i, m_table->columnWidth(i));

    m_frozenTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_frozenTable->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    updateFrozenTableGeometry();

    // connect the headers and scrollbars of both tableviews together
    connect(m_table->horizontalHeader(), &QHeaderView::sectionResized, this,
            &SVirtualTable::updateSectionWidth);
    connect(m_frozenTable->horizontalHeader(), &QHeaderView::sectionResized,
            this, &SVirtualTable::updateFrozenSectionWidth);
  }
}

void SVirtualTable::clearTable(bool resetPos) {
  auto* myModel = dynamic_cast<DefaultTableModel*>(m_table->model());
  if (!myModel) return;

  int colCount = myModel->columnCount();
  for (int i = 0; i < m_pageCount; ++i) {
    for (int col = 0; col < colCount; ++col) {
      QStandardItem* item = myModel->item(i, col);
      if (item == nullptr) {
        item = new QStandardItem();
        myModel->setItem(i, col, item);
      } else
        item->clearData();
    }
  }

  resetScroll(resetPos);
}

void SVirtualTable::onHeaderClicked(int logicalIndex) {
  emit headerSort(logicalIndex);
}

void SVirtualTable::updateLockGeo() {
  if (!m_locked || !m_lockIndicator) return;
  m_lockIndicator->setGeometry(0, 0, rect().width() - 8, 24);
}

void SVirtualTable::updateSectionWidth(int logicalIndex, int oldSize,
                                       int newSize) {
  if (logicalIndex < m_frozenCols) {
    m_frozenTable->setColumnWidth(logicalIndex, newSize);  // TODO?允许调序？
    updateFrozenTableGeometry();
  }
}

void SVirtualTable::updateFrozenSectionWidth(int logicalIndex, int,
                                             int newSize) {
  if (logicalIndex >= m_frozenCols) return;

  m_table->setColumnWidth(logicalIndex, newSize);
  updateFrozenTableGeometry();
}

void SVirtualTable::updateFrozenTableGeometry() {
  if (m_frozenCols == 0 || m_frozenTable == nullptr) return;

  int width = 0;
  for (int i = 0; i < m_frozenCols; ++i) {
    width += m_table->columnWidth(i);
  }
  m_frozenTable->setGeometry(
      m_table->verticalHeader()->width() + m_table->frameWidth(),
      m_table->frameWidth(), width,
      m_table->viewport()->height() + m_table->horizontalHeader()->height());
}

DefaultTableModel::DefaultTableModel(QObject* p) : QStandardItemModel(p) {}

QVariant DefaultTableModel::data(const QModelIndex& index,
                                 int role /*= Qt::DisplayRole*/) const {
  if (role == Qt::ToolTipRole) {
    QString tooltip = QStandardItemModel::data(index, role).toString();
    if (!tooltip.isEmpty()) return tooltip;

    QString txt = index.data(Qt::DisplayRole).toString();
    QFontMetrics fm(index.data(Qt::FontRole).value<QFont>());
    int txtWidth = fm.horizontalAdvance(txt);
    if (txtWidth >
        m_table->table()->horizontalHeader()->sectionSize(index.column())) {
      return txt;
    }

    QPixmap prefixImg = index.data(PrefixImgRole).value<QPixmap>();
    QPixmap postfixImg = index.data(PostfixImgRole).value<QPixmap>();
    QString postfixTxt = index.data(PostfixTxtRole).value<QString>();
    QRect postfixTxtRect = index.data(PostfixTxtRectRole).value<QRect>();
    if (!prefixImg.isNull() || !postfixImg.isNull()) {
      QRect rect = m_table->table()->visualRect(index);
      if (m_table->table()->horizontalHeader()->isVisible())
        rect.moveTop(rect.top() +
                     m_table->table()->horizontalHeader()->height());

      QPoint cusorPos = QCursor::pos();
      cusorPos = m_table->table()->mapFromGlobal(cusorPos);

      QRect r = rect;
      if (!postfixImg.isNull()) {
        r.setRight(r.right() - 4);
        r.setLeft(r.right() - postfixImg.width());
        r.setTop(r.bottom() - 4 - postfixImg.height());
        r.setHeight(postfixImg.height());

        if (r.contains(cusorPos))
          return index.data(PostfixTipRole).toString();
        else
          r.setRight(r.left() - 2);
      }

      if (!prefixImg.isNull()) {
        r.setRight(r.right() - txtWidth - 2);
        r.setLeft(r.right() - prefixImg.width());
        r.setTop(r.center().y() - prefixImg.height() / 2);
        r.setHeight(prefixImg.height());

        if (r.contains(cusorPos)) return index.data(PrefixTipRole).toString();
      }
    }
    if (!postfixTxt.isEmpty()) {
      QRect rect = m_table->table()->visualRect(index);
      if (m_table->table()->horizontalHeader()->isVisible())
        rect.moveTop(rect.top() +
                     m_table->table()->horizontalHeader()->height());

      QPoint cusorPos = QCursor::pos();
      cusorPos = m_table->table()->mapFromGlobal(cusorPos);

      QRect r = rect;
      r.setRight(r.right() - 4);
      r.setLeft(r.right() - postfixTxtRect.width());
      r.setTop(r.bottom() - 4 - postfixTxtRect.height());
      r.setHeight(postfixTxtRect.height());

      if (r.contains(cusorPos)) return tooltip;
    }
  } else if (role == Qt::BackgroundRole) {
    QString id = index.data(DataIdRole).toString();
    auto iter = m_flashInfos.find(id);
    if (iter != m_flashInfos.end()) {
      if (!iter->second.entireRow &&
          std::find(iter->second.cols.begin(), iter->second.cols.end(),
                    index.column()) == iter->second.cols.end())
        return QStandardItemModel::data(index, role);

      QColor bkClr = StyleMgr::instance().color("NewData");
      float alpha =
          float(FLASH_NUMBER - iter->second.flashCount) / FLASH_NUMBER;
      bkClr.setAlphaF(alpha < 0 ? 1 : alpha);
      return bkClr;
    }
  }

  return QStandardItemModel::data(index, role);
}

void DefaultTableModel::addFlashInfo(const FlashInfo& fi) {
  m_flashInfos[fi.id] = fi;
}

void DefaultTableModel::removeFlashInfo(const FlashInfo& fi) {
  m_flashInfos.erase(fi.id);
}

bool DefaultTableModel::flash() {
  for (auto iter = m_flashInfos.begin(); iter != m_flashInfos.end();) {
    if ((++iter->second.flashCount) > FLASH_NUMBER)
      iter = m_flashInfos.erase(iter);
    else
      ++iter;
  }
  if (!m_flashInfos.empty() && m_table) {
    QModelIndexList mlist;
    for (auto iter = m_flashInfos.begin(); iter != m_flashInfos.end(); ++iter) {
      QModelIndexList list = match(index(0, 0), DataIdRole, iter->first);
      mlist.append(list);
    }

    if (!mlist.isEmpty()) {
      std::sort(mlist.begin(), mlist.end());
      emit dataChanged(mlist[0],
                       index(mlist.rbegin()->row(), columnCount() - 1));
    }
  }

  return !m_flashInfos.empty();
}
